package Main;

import Include.*;
import Common.*;
import SentenceTranslator.*;

import java.util.*;

public class BlockTranslator {
    public static ASMBlock BlockTranslate(SymbolManager symbolManager, List<TACLine> tacBlock) {
        ASMBlock asmBlock = new ASMBlock();
        symbolManager.pushReg(REG.EBP, 0);
        asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.EBP));
        asmBlock.asmLines.add(ASMConstructor.construct_asm("mov", REG.EBP, REG.ESP));
        if (symbolManager.name_.equals("main")) {
            asmBlock.name = "_start";
        } else {
            asmBlock.name = symbolManager.name_;
            symbolManager.pushReg(REG.EAX, 0);
            symbolManager.pushReg(REG.EBX, 0);
            symbolManager.pushReg(REG.ECX, 0);
            symbolManager.pushReg(REG.EDX, 0);
            symbolManager.pushReg(REG.ESI, 0);
            asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.EAX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.EBX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.ECX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.EDX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("push", REG.ESI));
        }

        symbolManager.calUseInfo(tacBlock);
        symbolManager.setZeroLen();
        for (TACLine line : tacBlock) {
            System.out.println(line.toString() + " " + line.getSrc1().useInfo + "\t"
                    + line.getSrc2().useInfo + "\t" + line.getDst().useInfo + "\tscope "
                    + line.getScope());
            symbolManager.setScope(line.getScope());
            if (line.getSrc1().getOperType() == TacOperandType.VAR) {
                symbolManager.setUseInfo(line.getSrc1().getValue(), line.getSrc1().useInfo);
            }
            if (line.getSrc2().getOperType() == TacOperandType.VAR) {
                symbolManager.setUseInfo(line.getSrc2().getValue(), line.getSrc2().useInfo);
            }
            if (line.getDst().getOperType() == TacOperandType.VAR) {
                symbolManager.setUseInfo(line.getDst().getValue(), line.getDst().useInfo);
            }

            List<String> temRes = null;
            switch (line.getOp()) {
                case ASSIGN:
                    temRes = new AssignTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case CALL:
                    temRes = new CallTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case FUN_PARA:
                    temRes = new FunparaTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case FUN_RET:
                    temRes = new FunretTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case PARA:
                    temRes = new ParaTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case RET:
                    temRes = new RetTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case GOTO:
                    temRes = new GotoTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case LABEL:
                    temRes = new LabelTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case CREATLIST:
                    temRes = new CreatelistTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case IFEQ:
                case IFGE:
                case IFGT:
                case IFLE:
                case IFLT:
                case IFNEQ:
                    temRes = new IfTranslator().SentenceTranslate(symbolManager, line);
                    break;
                case DIV:
                case MUL:
                    temRes = new MulTranslator().SentenceTranslate(symbolManager, line);
                    break;
                default:
                    temRes = new CommonTranslator().SentenceTranslate(symbolManager, line);
                    break;
            }

            asmBlock.asmLines.addAll(temRes);
        }

        int stackLen = symbolManager.len_;
        if (stackLen > 0) {
            symbolManager.setEspBias(-4 * stackLen);
        } else if (stackLen < 0) {
            System.err.println(stackLen + " stack overflow");
        }

        if (symbolManager.name_.equals("main")) {
            symbolManager.popReg(REG.EBP);
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.EBP));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("mov", REG.EAX, "1"));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("mov", REG.EBX, "0"));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("int", "80h"));
        } else {
            symbolManager.popReg(REG.ESI);
            symbolManager.popReg(REG.EDX);
            symbolManager.popReg(REG.ECX);
            symbolManager.popReg(REG.EBX);
            symbolManager.popReg(REG.EAX);
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.ESI));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.EDX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.ECX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.EBX));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.EAX));
            symbolManager.popReg(REG.EBP);
            asmBlock.asmLines.add(ASMConstructor.construct_asm("pop", REG.EBP));
            asmBlock.asmLines.add(ASMConstructor.construct_asm("ret"));
        }

        return asmBlock;
    }

    // private static ASMLine construct_asm(String op, String... args) {
    // return new ASMLine(op, args);
    // }
}